﻿using MvvmCross.Core.ViewModels;
using Sidvall.Collections;
using Sidvall.IdentityManager.Data;
using Sidvall.IdentityManager.UI.Entities;
using Sidvall.IdentityManager.UI.Messaging;
using Sidvall.UI.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sidvall.IdentityManager.UI.ViewModels
{
    public partial class AspNetUsersCollectionViewModel
    {
        #region Public Members

        #region Title

        public string Title
        {
            get
            {
                return "Users: " + this.PageItem.Description;
            }
        }

        #endregion
        #region ActiveItem

        private AspNetUsers _ActiveItem;
        public AspNetUsers ActiveItem
        {
            get
            {
                return _ActiveItem;
            }
            set
            {
                _ActiveItem = value;
                RaisePropertyChanged("ActiveItem");
                RaisePropertyChanged("CanEditSelectedItem");
                RaisePropertyChanged("CanDelete");
            }
        }

        #endregion
        #region RowCountOptions

        private Sidvall.UI.Entities.SelectableKeyValueCollection<string, int> _RowCountOptions;
        public Sidvall.UI.Entities.SelectableKeyValueCollection<string, int> RowCountOptions
        {
            get
            {
                return _RowCountOptions;
            }
            private set
            {
                _RowCountOptions = value;
                RaisePropertyChanged(nameof(RowCountOptions));
            }
        }

        #endregion
        #region PageItem

        private PageItem _PageItem;
        public PageItem PageItem
        {
            get
            {
                if (_PageItem == null)
                {
                    this.PageItem = new PageItem()
                    {
                        DescriptionFormat = "{CurrentStartPosition} - {CurrentEndPosition} of {TotalRowCount}",
                    };
                }
                return _PageItem;
            }
            private set
            {
                _PageItem = value;
                RaisePropertyChanged(nameof(PageItem));
            }
        }

        #endregion
        #region CanDelete

        public bool CanDelete
        {
            get
            {
                return this.ActiveItem != null;
            }
        }

        #endregion
        #region CanEditSelectedItem

        public bool CanEditSelectedItem
        {
            get
            {
                return this.ActiveItem != null;
            }
        }

        #endregion
        #region Plugin1

        public Plugin Plugin1
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetFilterViewPlugin(0);
            }
        }

        #endregion
        #region Plugin2

        public Plugin Plugin2
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetFilterViewPlugin(1);
            }
        }

        #endregion
        #region Plugin3

        public Plugin Plugin3
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetFilterViewPlugin(2);
            }
        }

        #endregion
        #region Plugin4

        public Plugin Plugin4
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetFilterViewPlugin(3);
            }
        }

        #endregion
        #region Plugin5

        public Plugin Plugin5
        {
            get
            {
                return Sidvall.IdentityManager.UI.SystemContext.Current.GetFilterViewPlugin(4);
            }
        }

        #endregion

        // Filter
        #region TextFilter

        private string _TextFilter;
        public string TextFilter
        {
            get
            {
                return _TextFilter;
            }
            set
            {
                _TextFilter = value;
                RaisePropertyChanged("TextFilter");
            }
        }

        #endregion
        #region RowCount

        private int _RowCount = 100;
        public int RowCount
        {
            get
            {
                return _RowCount;
            }
            set
            {
                if (_RowCount != value)
                    _RowCount = value;
                RaisePropertyChanged(nameof(RowCount));
                this.PageItem.PageSize = this.RowCount;
            }
        }

        #endregion

        // Commands
        #region DeleteSelectedItemsCommand

        public ICommand DeleteSelectedItemsCommand
        {
            get
            {
                return new MvxCommand(async () => await DeleteSelectedItemsAsync());
            }
        }

        #endregion
        #region DeleteSelectedItemsAsync

        public async Task DeleteSelectedItemsAsync()
        {
            Task task = null;
            if (!this.CanDelete)
                return;
            using (var busyManager = new Sidvall.Data.BusyManager(this))
            {
                try
                {
                    var message = await Sidvall.UI.SystemContext.Current.DialogManager.ShowYesNoMessageAsync("Remove: " + this.ActiveItem.Id, "Are you sure?",
                        Sidvall.UI.Dialogs.MessageType.Question, false);
                    if (!message.AnswerIsYes)
                        return;

                    // Create tasks
                    var ids = new List<string>();
                    ids.Add(this.ActiveItem.Id);
                    var iMax = Sidvall.IdentityManager.UI.SystemContext.Current.ValidFilterPlugins.Count;
                    var tasks = new List<Task>();
                    for (int i = 0; i < iMax; i++)
                    {
                        tasks.Add(DeleteUsersAsync(ids, i));
                    }
                    await Task.WhenAll(tasks);

                    // Process results
                    for (int i = 0; i < iMax; i++)
                    {
                        var pluginItem = _PluginItems[i];
                        if (pluginItem.Result == null)
                            continue;
                        switch (pluginItem.Result.Type)
                        {
                            case PluginResultType.Failed:
                                throw new System.Exception(pluginItem.Result.ErrorMessage);
                            default:
                                break;
                        }
                    }
                    await Sidvall.IdentityManager.UI.SystemContext.Current.DataPortal.AspNetUsersManager.DeleteItemByPrimaryKeyAsync(this.ActiveItem.Id);
                    await DoLoadAsync();
                }
                catch (System.Exception ex)
                {
                    task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Unexpected Error", ex);
                }
                if (task != null)
                    await task;
            }
        }

        #endregion
        #region EditSelectedItemCommand

        public ICommand EditSelectedItemCommand
        {
            get
            {
                return new MvxCommand(EditSelectedItem);
            }
        }

        #endregion
        #region EditSelectedItem

        public void EditSelectedItem()
        {
            if (this.ActiveItem == null)
                return;
            ShowUser(this.ActiveItem.Id);
        }

        #endregion
        #region NewItemCommand

        public ICommand NewItemCommand
        {
            get
            {
                return new MvxCommand(NewItem);
            }
        }

        #endregion
        #region NewItem

        public void NewItem()
        {
            ShowUser(null);
        }

        #endregion
        #region PageChanged

        public ICommand PageChangedCommand
        {
            get
            {
                return new MvxCommand(async () => await PageChangedAsync());
            }
        }
        public async Task PageChangedAsync()
        {
            using (var busyManager = new Sidvall.Data.BusyManager(this))
            {
                try
                {
                    await DoLoadAsync();
                }
                catch (System.Exception ex)
                {
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Export Error", ex);
                }
            }
        }

        #endregion

        // View model
        #region LoadItemAsync

        protected async override Task<AspNetUsersCollection> LoadItemAsync()
        {
            PluginFilter newPluginFilter;

            var users = await SystemContext.Current.DataPortal.AspNetUsersManager.GetUsersAsync(this.TextFilter, false, true, true, this.RowCount, (int)this.PageItem.CurrentStartPosition - 1);
            var ids = (from o in users
                       select o.Id);
            var newPluginFilters = new PluginFilterCollection();
            var newPluginUsers = new PluginUserCollection();

            // Create tasks
            var iMax = Sidvall.IdentityManager.UI.SystemContext.Current.ValidFilterPlugins.Count;
            var tasks = new List<Task>();
            for (int i = 0; i < iMax; i++)
            {
                tasks.Add(LoadResultAsync(ids, false, i));
            }
            await Task.WhenAll(tasks);

            // Process results
            for (int i = 0; i < iMax; i++)
            {
                var pluginFilter = _PluginFilters[i];
                if (pluginFilter.FilterResult == null)
                    continue;
                switch (pluginFilter.FilterResult.Type)
                {
                    case PluginFilterResultType.Update:
                        users.Import(pluginFilter, false);
                        break;
                    case PluginFilterResultType.UpdateRemove:
                        users.Import(pluginFilter, true);
                        break;
                    case PluginFilterResultType.UpdateRemoveAdd:
                        users.Import(pluginFilter, true);
                        if (pluginFilter.FilterResult.Users != null)
                        {
                            newPluginFilter = null;
                            var userIds = users.ToHashSet(o => o.Id, true, System.StringComparer.OrdinalIgnoreCase);
                            var jMax = pluginFilter.FilterResult.Users.Count;
                            for (int j = 0; j < jMax; j++)
                            {
                                var pluginUser = pluginFilter.FilterResult.Users[j];
                                if ((!userIds.Contains(pluginUser.UserId)) && (!newPluginUsers.Contains(pluginUser.UserId)))
                                {
                                    newPluginUsers.Add(pluginUser);
                                    if (newPluginFilter == null)
                                    {
                                        newPluginFilter = newPluginFilters.Add(pluginFilter.PluginId, pluginFilter.FilterIndex, pluginFilter.FilterContext,
                                            new PluginFilterResult()
                                            {
                                                Type = pluginFilter.FilterResult.Type,
                                                Users = new PluginUserCollection(),
                                            });
                                    }
                                    newPluginFilter.FilterResult.Users.Add(pluginUser);
                                }
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
            if (newPluginUsers.Count > 0)
            {
                var newIds = (from o in newPluginUsers
                              select o.UserId);
                var newUsers = await SystemContext.Current.DataPortal.AspNetUsersManager.GetItemsByPrimaryKeysAsync(newIds);
                foreach (var newPluginFilterItem in newPluginFilters)
                    newUsers.Import(newPluginFilterItem, false);
                users.AddRange(newUsers);
            }
            users.AcceptChanges();
            return users;
        }

        #endregion
        #region GetDocumentFilterParameter

        public UserFilterParameter GetDocumentFilterParameter()
        {
            var item = new UserFilterParameter()
            {
                RowCount = this.RowCount,
                TextFilter = this.TextFilter,
            };
            return item;
        }

        #endregion
        #region SetDocumentFilterParameter

        public void SetDocumentFilterParameter(UserFilterParameter item, bool setRowCount)
        {
            this.TextFilter = item.TextFilter;
            if (setRowCount)
            {
                this.RowCount = item.RowCount;
            }
        }

        #endregion
        #region OnActiveEntityChanged

        protected override void OnActiveEntityChanged(Sidvall.Business.BusinessObjectChangeMode changeMode, Sidvall.Business.ChildChangedEventArgs childArgs, System.ComponentModel.PropertyChangedEventArgs propertyArgs)
        {
            switch (changeMode)
            {
                case Sidvall.Business.BusinessObjectChangeMode.NewBusinessObject:
                    if (this.ActiveEntity != null)
                        this.PageItem.TotalRowCount = this.ActiveEntity.TotalRowCount;
                    break;
                case Sidvall.Business.BusinessObjectChangeMode.MetaPropertyChanged:
                    break;
                case Sidvall.Business.BusinessObjectChangeMode.PropertyChanged:
                    break;
                case Sidvall.Business.BusinessObjectChangeMode.ChildCollectionChanged:
                    break;
                case Sidvall.Business.BusinessObjectChangeMode.ChildPropertyChanged:
                    break;
                case Sidvall.Business.BusinessObjectChangeMode.ChildMetaPropertyChanged:
                    break;
                default:
                    break;
            }
            RaiseAllPropertiesChanged();
        }

        #endregion
        #region Init

        public void Init(UserFilterParameter item)
        {
            this.UserFilterParameter = item;
        }

        #endregion
        #region StartAsync

        protected async override Task StartAsync()
        {
            this.PublishChange = true;
            this.RowCountOptions = Sidvall.UI.Entities.SelectableKeyValueManager.CreateFromValues(false, 25, 50, 100, 200, 500, 1000);
            SetDocumentFilterParameter(this.UserFilterParameter, true);
            _PluginFilters = new PluginFilterCollection();
            _PluginItems = new PluginItemCollection();
            foreach (var item in Sidvall.IdentityManager.UI.SystemContext.Current.ValidFilterPlugins)
            {
                _PluginFilters.Add(item.PluginId.ToString(), 0, null, null);
                _PluginItems.Add(item.PluginId.ToString(), null);
            }
            await ViewModelManager.LoadCacheAsync(false, null, this.EntityCache);
            await DoLoadAsync();
            Subscribe<PluginMessage>(OnPluginMessage);
            InitializePlugins();
            RaiseAllPropertiesChanged();
        }

        #endregion

        #endregion
        #region Private Members

        private UserFilterParameter UserFilterParameter { get; set; }
        private PluginFilterCollection _PluginFilters;
        private PluginItemCollection _PluginItems;
        private bool PublishChange { get; set; }

        #region ConfirmDelete

        private async Task ConfirmDelete(Sidvall.UI.Dialogs.MessageContext message)
        {
            Task task = null;
            if (message == null)
                return;
            if (!message.AnswerIsYes)
                return;
            using (var busyManager = new Sidvall.Data.BusyManager(this))
            {
                try
                {
                    await Sidvall.IdentityManager.UI.SystemContext.Current.DataPortal.AspNetUsersManager.DeleteItemByPrimaryKeyAsync(this.ActiveItem.Id);
                    await DoLoadAsync();
                }
                catch (System.Exception ex)
                {
                    task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Unexpected Error", ex);
                }
                if (task != null)
                    await task;
            }
        }

        #endregion
        #region DeleteUsersAsync

        private async Task DeleteUsersAsync(IEnumerable<string> userIds, int index)
        {
            Plugin item;
            PluginItem pluginItem;

            item = Sidvall.IdentityManager.UI.SystemContext.Current.ValidFilterPlugins[index];
            pluginItem = _PluginItems.FindItemById(item.PluginId.ToString());
            pluginItem.Result = await item.PluginInstance.DeleteUsersAsync(userIds);
        }

        #endregion
        #region InitializePlugins

        private void InitializePlugins()
        {
            Plugin plugin;
            ContextParameter parameter;
            int iMax;

            iMax = Sidvall.IdentityManager.UI.SystemContext.Current.FilterViewPluginCount;
            for (int i = 0; i < iMax; i++)
            {
                plugin = Sidvall.IdentityManager.UI.SystemContext.Current.ValidFilterViewPlugins[i];
                parameter = new ContextParameter()
                {
                    PluginId = plugin.PluginId.ToString(),
                };
                ShowViewModel(plugin.PluginInstance.FilterViewModelType, parameter, false, "CenterContent.PluginContent" + (i + 1).ToString());
            }
        }

        #endregion
        #region LoadResultAsync

        private async Task LoadResultAsync(IEnumerable<string> userIds, bool sortReversed, int index)
        {
            var item = Sidvall.IdentityManager.UI.SystemContext.Current.ValidFilterPlugins[index];
            var pluginFilter = _PluginFilters.FindItemById(item.PluginId.ToString());
            pluginFilter.FilterResult = await item.PluginInstance.GetUsersAsync(pluginFilter.FilterContext, userIds, this.TextFilter, this.RowCount, sortReversed);
            pluginFilter.FilterIndex = index;
        }

        #endregion
        #region OnPluginMessage

        private void OnPluginMessage(PluginMessage obj)
        {
            Plugin item;
            PluginFilter pluginFilter;

            if (this.ActiveEntity == null)
                return;
            switch (obj.PluginMessageType)
            {
                case PluginMessageType.FilterModified:
                    item = (from o in Sidvall.IdentityManager.UI.SystemContext.Current.ValidFilterPlugins
                            where o.PluginId.ToString() == obj.PluginId
                            select o).FirstOrDefault();
                    pluginFilter = _PluginFilters.FindItemById(item.PluginId.ToString());
                    pluginFilter.FilterContext = obj.FilterContext;
                    break;
                default:
                    break;
            }
        }

        #endregion
        #region OnSelectedItemsChanged

        private void OnSelectedItemsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged("CanDelete");
        }

        #endregion
        #region ShowUser

        public void ShowUser(string id)
        {
            var parameter = new UserParameter()
            {
                UserId = id,
            };
            this.UserFilterParameter = GetDocumentFilterParameter();
            this.ViewModelHistoryRegionItem.SetRequestParameterValue(this.UserFilterParameter);
            ShowViewModel<AspNetUsersViewModel>(parameter);
        }

        #endregion

        #endregion
    }
}